unit databaseformunit;

{$mode objfpc}{$H+}{$MACRO ON}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
  Buttons, database, LCLTranslator, languagehelper,

  { Frames for individual database pages: }
  database_base, database_actors,
  database_terms, database_classes, database_skills, database_items,
  database_weapons, database_armours, database_enemies, database_troops,
  database_states, database_tilesets, database_cevs, database_system,
  database_start, database_types, database_svbattle;

type

  { TDatabaseForm }

  TDatabaseFormPageId = (
    dfpiNoFrame = -1,
    dfpiActors = 0,
    dfpiClasses = 1,
    dfpiSkills = 2,
    dfpiItems = 3,
    dfpiWeapons = 4,
    dfpiArmours = 5,
    dfpiEnemies = 6,
    dfpiTroops = 7,
    dfpiStates = 8,
    dfpiAnimations = 9,
    dfpiTilesets = 10,
    dfpiCommonEvents = 11,
    dfpiSystem = 12,
    dfpiStart = 13,
    dfpiSvBattle = 14,
    dfpiAudio = 15,
    dfpiTypes = 16,
    dfpiTerms = 17
  );

  TDbFrameClass = class of TDatabaseBaseFrame;

  TDatabasePageDesc = record
    Id: TDatabaseFormPageId;
    Title: String;
    Frame: TDbFrameClass;
  end;

  TDatabaseForm = class(TForm)
    ApplyButton: TButton;
    OkBitBtn: TBitBtn;
    CancelBitBtn: TBitBtn;
    PageListBox: TListBox;
    PageSelectionLabel: TLabel;
    PageSelectionPanel: TPanel;
    PageSelectorSplitter: TSplitter;
    DecisionButtonsPanel: TPanel;
    PageFrame: TDatabaseBaseFrame;
    procedure ApplyButtonClick(Sender: TObject);
    procedure CancelButtonClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure OkButtonClick(Sender: TObject);
    procedure PageListBoxSelectionChange(Sender: TObject; User: boolean);
    function GetCurrentFrameType: TDatabaseFormPageId;
    function CreatePageFrame(PageId: TDatabaseFormPageId): TDatabaseBaseFrame;
  private
    EditedDb: TDatabase;
    procedure SetUpPages;
  public
    function ShowModal: Integer; override;
    procedure UpdateLanguage(Code: String);
  end;

const
  DbPageData: array[0..17] of TDatabasePageDesc = (
    (Id: dfpiActors; Title: ActorsHeader; Frame: TDatabaseActorsFrame),
    (Id: dfpiClasses; Title: ClassesHeader; Frame: TDatabaseClassesFrame),
    (Id: dfpiSkills; Title: SkillsHeader; Frame: TDatabaseSkillsFrame),
    (Id: dfpiItems; Title: ItemsHeader; Frame: TDatabaseItemsFrame),
    (Id: dfpiWeapons; Title: WeaponsHeader; Frame: TDatabaseWeaponsFrame),
    (Id: dfpiArmours; Title: ArmoursHeader; Frame: TDatabaseArmoursFrame),
    (Id: dfpiEnemies; Title: EnemiesHeader; Frame: TDatabaseEnemiesFrame),
    (Id: dfpiTroops; Title: TroopsHeader; Frame: TDatabaseTroopsFrame),
    (Id: dfpiStates; Title: StatesHeader; Frame: TDatabaseStatesFrame),
    (Id: dfpiAnimations; Title: 'Animations'; Frame: nil),
    (Id: dfpiTilesets; Title: TilesetsHeader; Frame: TDatabaseTilesetsFrame),
    (Id: dfpiCommonEvents; Title: CevsHeader; Frame: TDatabaseCevsFrame),
    (Id: dfpiSystem; Title: SystemHeader; Frame: TDatabaseSystemFrame),
    (Id: dfpiStart; Title: StartHeader; Frame: TDatabaseStartFrame),
    (Id: dfpiSvBattle; Title: SvBattleHeader; Frame: TDatabaseSvBattleFrame),
    (Id: dfpiAudio; Title: 'Audio'; Frame: nil),
    (Id: dfpiTypes; Title: TypesHeader; Frame: TDatabaseTypesFrame),
    (Id: dfpiTerms; Title: 'Terms'; Frame: TDatabaseTermsFrame)
  );

var
  DatabaseForm: TDatabaseForm;

implementation

uses Math, globals;

{$R *.lfm}

{ TDatabaseForm }

procedure TDatabaseForm.OkButtonClick(Sender: TObject);
begin
   Game.Db.SetData(EditedDb);
   Game.DbIsDirty := True;
   EditedDb.Free;
   Close;
end;

function TDatabaseForm.GetCurrentFrameType: TDatabaseFormPageId;
var
  I: Integer;
begin
 GetCurrentFrameType := dfpiNoFrame;

 if PageFrame = nil then
   Exit;

  for I := Low(DbPageData) to High(DbPageData) do begin
    if PageFrame is DbPageData[I].Frame then begin
      GetCurrentFrameType := DbPageData[I].Id;
      Exit
    end;
  end;
end;

procedure TDatabaseForm.PageListBoxSelectionChange(Sender: TObject;
  User: boolean);
var
  SelectedPage: TDatabaseFormPageId;
begin
  SelectedPage := TDatabaseFormPageId(PageListBox.ItemIndex);
  if (EditedDb <> nil) and (SelectedPage <> GetCurrentFrameType) then begin
    if PageFrame <> nil then
      PageFrame.Free;

    PageFrame := CreatePageFrame(SelectedPage);
  end;
end;

function TDatabaseForm.CreatePageFrame(PageId: TDatabaseFormPageId):
                                               TDatabaseBaseFrame;
var
  PageDesc: TDatabasePageDesc;
  Page: TDatabaseBaseFrame;
  PageClass: TDbFrameClass;
begin
  Page := nil;

  if (Integer(PageId) >= Low(DbPageData)) and (Integer(PageId) <= High(DbPageData)) then begin
    PageDesc := DbPageData[Integer(PageId)];
    PageClass := PageDesc.Frame;
    if PageClass <> nil then
      Page := PageClass.Create(Self);
  end;

  if Page <> nil then begin
    Page.Visible := False;
    Page.DoubleBuffered := True;
    Page.Parent := Self;
    Page.Align := alClient;
    Page.TabOrder := 1;
    Page.HandleNeeded;
    Page.SetDatabase(EditedDb);
    Page.UpdateLanguage(EditorLanguage);
    Page.Visible := True
  end;

  CreatePageFrame := Page;
end;

procedure TDatabaseForm.SetUpPages;
var
  I: Integer;
begin
  PageListBox.Items.BeginUpdate;
  for I := Low(DbPageData) to High(DbPageData) do begin
    if PageListBox.Items.Count <= I then
      PageListBox.Items.Add(DbPageData[I].Title)
    else
      PageListBox.Items[I] := DbPageData[I].Title
  end;
  PageListBox.Items.EndUpdate;
end;

procedure TDatabaseForm.CancelButtonClick(Sender: TObject);
begin
   EditedDb.Free;
   Close;
end;

procedure TDatabaseForm.FormClose(Sender: TObject;
                                  var CloseAction: TCloseAction);
begin
  if PageFrame <> nil then begin
    PageFrame.Free;
    PageFrame := nil;
  end;
end;

procedure TDatabaseForm.FormCreate(Sender: TObject);

  procedure SwapButtons(A, B: TCustomButton);
  var
    Tmp: Integer;
  begin
    Tmp := A.Left;
    A.Left := B.Left;
    B.Left := Tmp;

    Tmp := A.TabOrder;
    A.TabOrder := B.TabOrder;
    B.TabOrder := Tmp;
  end;

begin
  (* Make sure our window is not larger than screen.
  Ideally we should use a special layout compact for smaller screens *)
  Width := Min(Screen.Width - 20, Width);
  Height := Min(Screen.Height - 20, Height);

  { On Gnome, the button order is: Apply Cancel OK
    On Windows, the button oder is: OK Cancel Apply
    On KDE, the button order is: OK Apply Cancel
    On Mac, the button order is: Cancel Ok (we don't support Mac so just treat it as a GTK+ variant)}
  {$IF Defined(LCLGtk) or Defined(LCLGtk2) or Defined(LCLGtk3) or Defined(LCLCarbon) or Defined(LCLCocoa)}
    SwapButtons(OkBitBtn, ApplyButton);
  {$ELSEIF Defined(LCLQt) or Defined(LCLQt5)}
    SwapButtons(CancelBitBtn, ApplyButton);
  {$ENDIF}

  SetUpPages;
  PageListBox.ItemIndex := 0;
end;

procedure TDatabaseForm.ApplyButtonClick(Sender: TObject);
begin
   Game.Db.SetData(EditedDb);
   Game.DbIsDirty := True;
end;

function TDatabaseForm.ShowModal: Integer;
begin
   if Game.Db <> nil then begin
     EditedDb := TDatabase.Create;
     EditedDb.SetData(Game.Db);

     if PageFrame <> nil then
       PageFrame.Free;

     PageFrame := CreatePageFrame(TDatabaseFormPageId(PageListBox.ItemIndex));

     Result := inherited;
   end
   else begin
     Result := 0;
   end;
end;

procedure TDatabaseForm.UpdateLanguage(Code: String);
begin
  SetUpPages;
end;

end.

